'''
	生成抽象语法树
'''
import os, sys
sys.path.append(os.getcwd()+'\\parser')
from common import *
from enums import *
from ast_node import *
from error.error import syntax_error;

class Token:
	def __init__(self,type,value,lineNumber):
		self.tokenType=type;
		self.value=value;
		#字符所在行号
		self.lineNumber=lineNumber;

	def viewTree(self):
		return {
			'tokenType':self.tokenType,'value':self.value,'lineNumber':self.lineNumber
		};


class Parser:
	def __init__(self,lexer):
		self.lexer=lexer;
		# tokens列表
		self.tokens=lexer.lexing();
		# token当前位置
		self.tokenPos=0;
		# 当前token
		self.current_token=self.tokens[self.tokenPos];

	def parser(self):
		# 获取程序所有节点
		node=self.program();
		# 如果当前不是文件末端记号
		if self.current_token.tokenType!=EOF:
			syntax_error(self.current_token,'获取节点错误');
		return node;

	# 添加获取程序所有节点方法
	def program(self):
		# 获取块节点
		block_node = self.block()
		# 创建程序节点
		node = Program('start_program', block_node)
		return node  # 返回程序节点

	# 构造块节点的方法
	def block(self):
		# 构造导入文件节点的方法
		import_file = self.import_file_node()
		# 构造声明节点的方法
		declarations = self.declarations()
		# 添加获取复合语句节点列表
		compound_statement = self.compound_statement()

		# 块节点由声明节点和符合语句节点组成
		node = Block(import_file,declarations, compound_statement)
		return node

	# 构造导入文件节点的方法
	def import_file_node(self):
		# 声明节点包含多个变量声明节点
		import_list = []
		# 如果当前记号为导入文件
		if self.current_token.tokenType == IMPORT:
			# 验证记号
			self.nextToken(IMPORT)
			# 遍历导入文件名称
			while self.current_token.tokenType == IMPORT or self.current_token.tokenType == STRING:
				# 声明列表中添加导入文件
				import_list.extend(self.import_declaration());
				# 验证分号
				self.nextToken(SEMI);
				# if self.current_token.tokenType == IMPORT:
				#   self.import_file_node()
				#   break;

		return import_list  # 返回导入文件节点列表
	# 构造导入文件节点的方法
	def import_declaration(self):
		str_nodes = [Str(self.current_token)];
		# 一组变量声明的类型节点
		type_node = self.type_spec();
		mport_declarations = [Import(str_node, type_node) for str_node in str_nodes];
		return mport_declarations;

	# 构造声明节点的方法
	def declarations(self):
		# 声明节点包含多个变量声明节点
		declarations = [];

		# 如果当前记号为变量
		while True:
			# while self.current_token.tokenType == Enums.VAR.value:
			if self.current_token.tokenType == Enums.VAR.value:
				# 验证记号
				self.nextToken(VAR)
				# 遍历变量名称
				while self.current_token.tokenType == VARIABLE:
					# 声明列表中添加变量声明
					declarations.extend(self.variable_declaration());
					# 验证分号
					self.nextToken(SEMI);
					if self.current_token.tokenType != VAR:
						break;
			elif self.current_token.tokenType == Enums.FUNCTION.value:  # 当前记号类型是函数时
				self.nextToken(Enums.FUNCTION.value)  # 验证函数类型
				# 获取函数名称
				function_name = self.current_token.value
				self.nextToken(Enums.VARIABLE.value)  # 验证函数名称
				params = []  # 参数列表
				if self.current_token.tokenType == Enums.LPAREN.value:  # 如果遇到左括号
					self.nextToken(Enums.LPAREN.value)  # 验证左括号
					params = self.formal_parameter_list()  # 获取参数列表
					self.nextToken(Enums.RPAREN.value)  # 验证右括号
				# 验证冒号---函数比过程多一个函数数据类型
				self.nextToken(Enums.LEFT_RPAREN.value)
				type_node = self.type_spec()  # 获取函数的返回类型节点
				# print(self.current_token.tokenType)
				# self.nextToken(Enums.SEMI.value)  # 验证分号
				block_node = self.block()  # 获取过程中的块

				self.nextToken(Enums.RIGHT_RPAREN.value);
				# 创建包含参数的函数声明对象
				function_decl = Function(function_name, params, block_node,type_node)
				# 声明列表末尾添加新的过程声明
				declarations.append(function_decl)
				# self.nextToken(Enums.SEMI.value)  # 验证分号
			else:  # 否则
				break  # 结束声明遍历
		return declarations  # 返回声明节点列表

	# 构造变量声明节点的方法
	def variable_declaration(self):
		# 第一个变量声明节点添加到变量声明节点列表
		var_nodes = [Variable(self.current_token)]
		self.nextToken(VARIABLE)  # 验证变量名称记号
		while self.current_token.tokenType == COMMA:  # 遍历逗号
			self.nextToken(COMMA)  # 验证逗号
			# 添加变量节点到变量节点列表
			var_nodes.append(Variable(self.current_token))
			self.nextToken(VARIABLE)  # 验证变量名称记号
		self.nextToken(ASSIGN)  # 验证等号
		type_node = self.type_spec()  # 一组变量声明的类型节点
		# 生成变量声明列表
		var_declarations = [VarDecl(var_node, type_node) for var_node in var_nodes]
		return var_declarations  # 返回变量声明节点列表

	# 构造变量类型节点的方法
	def type_spec(self):
		# 获取当前记号
		token = self.current_token
		# 如果是整数类型
		if token.tokenType == INTEGER:
			# 验证整数记号
			self.nextToken(INTEGER)
		# 如果是浮点数类型
		elif token.tokenType == FLOAT:
			self.nextToken(FLOAT)
		# 如果是字符串类型
		elif token.tokenType == STRING:
			self.nextToken(STRING)
		# 如果是布尔类型
		elif token.tokenType == BOOLEAN:
			self.nextToken(BOOLEAN)
		# 创建类型节点
		node = Type(token) 
		return node  # 返回类型节点

	# 获取变量节点
	def variable(self):
		# 获取变量节点
		node=Variable(self.current_token);
		self.nextToken(VARIABLE);
		return node;

	# 获取加减乘除变量节点
	def variable_complex(self):
		# 获取上一个token中的变量节点
		node=Variable(self.tokens[self.tokenPos-1]);
		return node;
	# 添加获取空语句节点的方法
	def empty(self):
		return NoOperator()  # 返回空语句节点
		# 添加获取语句列表节点

	# 添加获取复合语句节点列表
	def compound_statement(self):
		# self.eat(BEGIN)

		# 包含节点为语句列表
		nodes=self.statement_list();
		# self.eat(END)
		# 创建复合语句节点对象
		root=Compound();
		# 将语句节点列表添作为复合语句节点的子节点列表
		root.children=nodes;
		# 返回复合语句节点对象
		return root;

	def statement_list(self):
		# 获取第一条语句节点
		node=self.statement();
		# 添加第一条语句节点到列表
		nodes=[node];
		# 如果遇到分号

		# while self.current_token.tokenType==SEMI:

		while self.current_token.tokenType in (
			Enums.SEMI.value, # ;
			# Enums.VARIABLE.value, # variable
			Enums.IF.value, # if
			Enums.FOR.value, # for
			Enums.PRINT.value, # print
			Enums.LEN.value, # len
			Enums.GETTYPE.value # gettype
		):
			if self.current_token.tokenType==SEMI:
				# 验证分号
				self.nextToken(SEMI);
			# 添加下一条语句节点到列表
			nodes.append(self.statement());

		if self.current_token.tokenType==VARIABLE:# 如果只遇到一个名称而非语句
			syntax_error(self.current_token,'error');
		# 返回语句节点列表
		return nodes;

	# 添加获取语句节点
	def statement(self):
		# 函数调用
		if (self.current_token.tokenType == Enums.VARIABLE.value and self.peekNextToken() == '('):
			#获取过程或函数调用节点
			node = self.call_statement()
		# 如果遇到一个名称，说明是赋值语句
		elif self.current_token.tokenType==VARIABLE:
			# 获取赋值语句节点
			node=self.assignment_statement();
		elif self.current_token.tokenType == Enums.IF.value:
			node = self.if_statement()
		elif self.current_token.tokenType == Enums.FOR.value:
			node = self.for_statement()
		elif self.current_token.tokenType == Enums.PRINT.value:
			node = self.print_statement();
		elif self.current_token.tokenType == Enums.LEN.value:
			node = self.length_statement();
		elif self.current_token.tokenType == Enums.GETTYPE.value:
			node = self.get_type_statement();
		else:
			# 否则就是空语句
			# 返回空语句节点
			node=self.empty();
		return node;

	# 添加获取赋值语句节点的方法
	def assignment_statement(self):
		# 获取变量名称节点
		left=self.variable();
		token=self.current_token;
		if token.tokenType==ASSIGN:
			# 验证赋值符
			self.nextToken(ASSIGN);
			# 获取表达式节点
			right=self.expression();
			# 组成赋值语句节点
			node=Assign(left,token,right);
		elif token.tokenType==PLUS_ASSIGN:
			# 验证加法赋值符
			# 获取表达式节点
			right=self.expression();
			# 组成赋值语句节点
			node=PlusAssign(left,token,right);
		elif token.tokenType==MINUS_ASSIGN:
			# 验证减法赋值符
			# 获取表达式节点
			right=self.expression();
			# 组成赋值语句节点
			node=MinusAssign(left,token,right);
		elif token.tokenType==MUL_ASSIGN:
			# 验证乘法赋值符
			# 获取表达式节点
			right=self.expression();
			# 组成赋值语句节点
			node=MulAssign(left,token,right);
		elif token.tokenType==DIV_ASSIGN:
			# 验证除法赋值符
			# 获取表达式节点
			right=self.expression();
			# 组成赋值语句节点
			node=DivAssign(left,token,right);
		elif token.tokenType==IMPORT:
			# 组成赋值语句节点
			node=Import(left,token);
		return node;


	def expression(self):
		node=self.term();
		# PLUS 加,MINUS 减
		# EQUAL== 等于,NOTEQUAL != 不等于,GREATER_THAN > 大于,LESS_THAN < 小于,GREATER_THAN_EQUAL >= 大于等于,LESS_THAN_EQUAL <= 小于等于
		# NOTEQUAL != 不等于,
		# AND 逻辑与,OR 逻辑或,NOT 逻辑非
		# 
		while self.current_token.tokenType in (
			# 加减
			Enums.PLUS.value,Enums.MINUS.value,
			Enums.EQUAL.value,PLUS_ASSIGN,MINUS_ASSIGN,MUL_ASSIGN,DIV_ASSIGN,NOTEQUAL,GREATER_THAN,LESS_THAN,GREATER_THAN_EQUAL,LESS_THAN_EQUAL,
			Enums.AND.value,Enums.OR.value,Enums.NOT.value,
			Enums.BOOLEAN.value):

			token=self.current_token;

			if token.tokenType in (Enums.PLUS.value,Enums.MINUS.value,
			Enums.EQUAL.value,PLUS_ASSIGN,MINUS_ASSIGN,MUL_ASSIGN,DIV_ASSIGN,
			Enums.AND.value,Enums.OR.value,Enums.NOT.value):

				if token.tokenType==PLUS_ASSIGN: # += 加等
					self.nextToken(PLUS_ASSIGN);
					token=Token(PLUS,'+',0);
				elif token.tokenType==MINUS_ASSIGN: # -= 减等
					self.nextToken(MINUS_ASSIGN);
					token=Token(MINUS,'-',0);
				elif token.tokenType==MUL_ASSIGN: # *= 乘等
					self.nextToken(MUL_ASSIGN);
					token=Token(MUL,'*',0);
				elif token.tokenType==DIV_ASSIGN: # /= 除等
					self.nextToken(DIV_ASSIGN);
					token=Token(DIV,'/',0);
				else:
					self.nextToken(token.tokenType);
				node = BinaryOperator(node,token,self.term());

			elif token.tokenType in (Enums.EQUAL.value,Enums.NOTEQUAL.value,Enums.GREATER_THAN.value,Enums.LESS_THAN.value,Enums.GREATER_THAN_EQUAL.value,Enums.LESS_THAN_EQUAL.value):
				# ===============比较运算================#
				# EQUAL == 等于,NOTEQUAL 不等于,
				# GREATER_THAN > 大于,LESS_THAN < 小于,
				# GREATER_THAN_EQUAL >= 大于等于,LESS_THAN_EQUAL <= 小于等于
				self.nextToken(token.tokenType);
				node = ComparisonOperation(node,token,self.term());

			elif token.tokenType == Enums.BOOLEAN.value:

				# ===============布尔运算================#
				# BOOLEAN 布尔
				self.nextToken(Enums.BOOLEAN.value);
				node = BooleanOperation(node,token,self.term());

			# elif token.tokenType in (Enums.AND.value,Enums.OR.value,Enums.NOT.value):
			#   # ===============逻辑运算================#
			#   # AND 逻辑与,OR 逻辑或,NOT 逻辑非
			#   self.nextToken(token.tokenType);
			#   node = ComparisonOperation(node,token,self.term());

		return node;

	def term(self):
		node=self.factor();
		while self.current_token.tokenType in (Enums.MUL.value,Enums.DIV.value):
			token=self.current_token;
			# 乘除
			if token.tokenType in (Enums.MUL.value,Enums.DIV.value):
				self.nextToken(token.tokenType);
			node = BinaryOperator(node,token,self.factor());
		return node;

	def factor(self):
		current_token=self.current_token;
		# 加减乘除
		if current_token.tokenType in (Enums.PLUS.value,
			Enums.MINUS.value,
			Enums.MUL.value,
			Enums.DIV.value,
			Enums.BOOLEAN.value
		):
			self.nextToken(current_token.tokenType);
			return UnaryOperator(current_token,self.factor());

		elif current_token.tokenType in (PLUS_ASSIGN,MINUS_ASSIGN,MUL_ASSIGN,DIV_ASSIGN):
			# 返回上一个token中的变量
			return self.variable_complex();

		elif current_token.tokenType==NOT:
			self.nextToken(NOT);
			return LogicWron(current_token,self.factor());

		elif current_token.tokenType in (INTEGER ,FLOAT):
			self.nextToken(current_token.tokenType);
			#返回数字节点
			node= Num(current_token);
			return node;

		elif current_token.tokenType==STRING:
			self.nextToken(STRING);
			#返回字符串节点
			return Str(current_token);

		elif current_token.tokenType==Enums.BOOLEAN.value:
			self.nextToken(STRING);
			#返回字符串节点
			return Boolean(current_token);

		elif current_token.tokenType==SINGLE_QUOTES:
			self.nextToken(SINGLE_QUOTES);
			#执行表达式函数
			node=self.expression();
			self.nextToken(SINGLE_QUOTES);
			#返回括号中的表达试节点
			return node;

		elif current_token.tokenType==LPAREN:
			self.nextToken(LPAREN);
			#执行表达式函数
			node=self.expression();
			self.nextToken(RPAREN);
			#返回括号中的表达试节点
			return node;
		# print('factor:',current_token.tokenType);
		# print('factor:',self.peekNextToken());
		# 函数调用
		if (current_token.tokenType == Enums.VARIABLE.value and self.peekNextToken() == '('):
			#获取过程或函数调用节点
			node = self.call_statement()
		else:
			# 获取变量节点
			node=self.variable();
			return node;

	# 创建参数列表节点的方法(循环完所有行参数)
	def formal_parameter_list(self):
		if self.current_token.tokenType != Enums.VARIABLE.value:  # 如果没有参数
			return []  # 返回空列表
		param_nodes = self.formal_parameters()  # 添加同类型参数节点到参数节点列表
		# 当前记号是逗号时还有更多参数
		while self.current_token.tokenType == Enums.COMMA.value:
			self.nextToken(Enums.COMMA.value)  # 验证逗号
			param_nodes.extend(self.formal_parameters())  # 添加更多参数节点到参数节点列表
		return param_nodes  # 返回参数节点列表

	# 创建参数节点的方法  （循环完每一行参数）
	def formal_parameters(self):
		param_nodes = []  # 参数节点列表
		param_tokens = [self.current_token]  # 参数记号列表
		self.nextToken(Enums.VARIABLE.value)  # 验证第一个参数名称
		while self.current_token.tokenType == Enums.COMMA.value:  # 当遇到逗号时
			self.nextToken(Enums.COMMA.value)  # 验证逗号
			param_tokens.append(self.current_token)  # 添加记号到参数记号列表
			self.nextToken(Enums.VARIABLE.value)  # 验证参数名称
		type_node = self.type_spec()  # 获取参数类型节点
		for param_token in param_tokens:  # 遍历参数记号列表
			# 通过参数记号创建参数节点
			param_node = Param(Variable(param_token), type_node)
			param_nodes.append(param_node)  # 添加参数节点到参数节点列表
		return param_nodes  # 返回参数节点列表

	def nextToken(self,tokenType):
		if self.current_token.tokenType==tokenType:
			index=self.tokenPos+1;
			self.current_token=self.tokens[index];
			self.tokenPos=index;
		else:
			syntax_error(self.current_token,'获取下一个token错误');

	def prevToken(self,tokenType):
		if self.current_token.tokenType==tokenType:
			self.current_token=self.tokens[self.tokenPos-1];
		else:
			syntax_error(self.current_token,'获取上一个token错误');
	#偷看下一个token
	def peekNextToken(self):
		token=self.tokens[self.tokenPos+1];
		return token.value;
		



	# ======================== start 内置语句 ====================== #
	# 添加获条件控制语句IF节点的方法
	def if_statement(self):
		self.nextToken(Enums.IF.value)  # 验证IF
		# 获取条件语句表达式节点(IF XXX里面的XX，是一个BINOP表达式)
		con = self.expression()
		# self.nextToken(THEN)  # 验证THEN
		self.nextToken(Enums.LEFT_RPAREN.value)  # 验证 {
		# 获取THEN后面的分支块节点
		then_nodes = self.statement_list()
		then_root = Compound()  # 创建复合语句节点对象
		# 将语句节点列表添作为复合语句节点的子节点列表
		then_root.children = then_nodes
		self.nextToken(Enums.RIGHT_RPAREN.value)  # 验证 }

		if self.current_token.tokenType==Enums.ELSE.value:
			self.nextToken(Enums.ELSE.value)  # 验证 ELSE
			self.nextToken(Enums.LEFT_RPAREN.value)  # 验证 {
			# 获取ELSE后面的分支块节点
			else_nodes = self.statement_list()

			self.nextToken(Enums.RIGHT_RPAREN.value)  # 验证 }

			# 创建复合语句节点对象
			else_root = Compound()
			# 将语句节点列表添作为复合语句节点的子节点列表
			else_root.children = else_nodes
		else:
			else_root = '';

		node=If(con,then_root,else_root);
		# 返回赋值语句节点
		return node

	# 添加循环控制语句FOR节点的方法
	def for_statement(self):
		self.nextToken(Enums.FOR.value)  # 验证FOR
		start_node = self.assignment_statement()  # 循环开始节点是一个ASSIGN节点
		self.nextToken(Enums.TO.value)  # 验证TO
		end_node = self.expression()  # 循环终止节点是一个expr节点
		# # 如果遇到{，说明是BLOCK结构
		self.nextToken(Enums.LEFT_RPAREN.value)  # 验证 {

		left_rparen_nodes = self.statement_list()
		# 循环体节点是复合语句
		left_rparen_root = Compound()
		# 将语句节点列表添作为复合语句节点的子节点列表
		left_rparen_root.children = left_rparen_nodes;

		# # 验证 }
		self.nextToken(Enums.RIGHT_RPAREN.value)
		# print('jjj1')

		# print('for_statement:',left_rparen_root.viewTree());
		# exit();
		node = For(start_node, end_node, left_rparen_root)
		# 返回循环控制语句FOR节点
		return node

	#过程调用或函数调用通用
	def call_statement(self):
		"""proccall_statement : ID LPAREN (expr (COMMA expr)*)? RPAREN"""
		token = self.current_token
		#解析出过程调用时使用的名称
		proc_name = self.current_token.value
		self.nextToken(Enums.VARIABLE.value)          #过程调用名称是一个ID类型的token
		self.nextToken(Enums.LPAREN.value)            #解析左括号
		actual_params = []    #过程实参列表
		if self.current_token.tokenType != Enums.RPAREN.value: #不是右括号
			node = self.expression()  #解析出过程调用时括号内的第1个实参expr节点
			actual_params.append(node) #第1个expr节点放入实参列表
		while self.current_token.tokenType == Enums.COMMA.value:#解析出第1个逗号后面的所有实参expr节点
			self.nextToken(Enums.COMMA.value)
			node = self.expression()
			actual_params.append(node) #把全部逗号分隔的expr节点全部放入实参列表
		self.nextToken(Enums.RPAREN.value)  #右括号
		# self.nextToken(Enums.SEMI.value)  #分号
		node = Call(       #最终生成过程调用节点：包括过程名称和实参列表
			proc_name=proc_name,
			actual_params=actual_params,
			token=token,
		)
		return node


	# ======================== end 内置语句 ====================== #


	# ======================== start 内置函数 ====================== #
	# 打印输出
	def print_statement(self):
		# 验证 print
		self.nextToken(Enums.PRINT.value)
		self.nextToken(Enums.LPAREN.value)  # 验证左括号
		params=[self.expression()]        # 取到第1个参数
		while (self.current_token.tokenType != Enums.RPAREN.value):  #不是右括号
			self.nextToken(Enums.COMMA.value)    # 验证逗号
			params.append(self.expression())   # 把括号里的每个参数都读完
		self.nextToken(Enums.RPAREN.value)  # 验证右括号
		node=Print(params=params)
		return node  # 返回屏幕打印节点

	# 获取字符串长度
	def length_statement(self):
		# 验证 len
		self.nextToken(Enums.LEN.value)
		self.nextToken(Enums.LPAREN.value)  # 验证左括号
		# 取到参数
		params=self.expression()
		self.nextToken(Enums.RPAREN.value)  # 验证右括号
		node=Length(params)
		# 返回屏幕打印节点
		return node

	# 获取变量类型
	def get_type_statement(self):
		# 验证 type
		self.nextToken(Enums.GETTYPE.value)
		self.nextToken(Enums.LPAREN.value)  # 验证左括号
		# 取到参数
		params=self.expression()
		self.nextToken(Enums.RPAREN.value)  # 验证右括号
		node=GetType(params)
		# 返回屏幕打印节点
		return node



	# ======================== end 内置函数 ====================== #


